package com.gitee.fitness.config;

import org.springframework.amqp.core.*;
import org.springframework.amqp.rabbit.config.RetryInterceptorBuilder;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.rabbit.retry.MessageRecoverer;
import org.springframework.amqp.rabbit.retry.RepublishMessageRecoverer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.retry.interceptor.RetryOperationsInterceptor;

import java.util.HashMap;
import java.util.Map;

@Configuration
public class RabbitMqConfig {

    public static final String QUEUE_NAME = "test.queue";

    public static final String QUEUE_RETRY_NAME = "test.retry.queue";

    public static final String QUEUE_RETRY1_NAME = "test.retry1.queue";

    public static final String EXCHANGE_NAME = "test.exchange";
    // 死信队列名称
    private static final String DEAD_LETTER_QUEUE_NAME = "test.dlx.queue";
    // 死信队列交换机名称
    public static final String DEAD_LETTER_EXCHANGE_NAME = "test.dlx.exchange";

    // 最终死信队列名称
    public static final String DEAD_LETTER_FINAL_QUEUE_NAME = "test.final.dlx.queue";
    // 最终死信队列交换机名称
    public static final String DEAD_LETTER_FINAL_EXCHANGE_NAME = "test.final.dlx.exchange";

    @Bean
    Queue testQueue() {
        System.out.println("🛠️ 正在创建持久化业务队列: testQueue");
        Map<String, Object> args = new HashMap<>();
        // ⭐ 核心配置 1: 指定当前队列的死信发往哪个交换机 ⭐
        // 当消息被 NACK(requeue=false) 或在当前队列过期，会被发到这个交换机
        args.put("x-dead-letter-exchange", DEAD_LETTER_FINAL_QUEUE_NAME); // 指向上面定义的 DLX

        // ⭐ 可选配置：指定死信的路由键，不指定则使用原消息的路由键 ⭐
        args.put("x-dead-letter-routing-key", "test.final.dlx.exchange");

        // ⭐ 可选配置：给业务队列的消息设置 TTL (如果在队列里长时间没被消费也会死信) ⭐
        // args.put("x-message-ttl", 300000); // 比如 5 分钟，防止消息永远积压在业务队列

        // 队列本身也要持久化
        return new Queue(QUEUE_NAME, true, false, false, args);
    }

    @Bean
    TopicExchange exchange() {
        return new TopicExchange(EXCHANGE_NAME);
    }


    @Bean
    Binding binding() {
        return BindingBuilder.bind(testQueue()).to(exchange()).with("api.#");
    }
//
//    /**
//     * 死信队列
//     *
//     * @return {@link Queue }
//     */
//    @Bean
//    Queue deadLetterQueue() {
//        return QueueBuilder.durable(DEAD_LETTER_QUEUE_NAME).build();
//    }
//
//    /**
//     * dlx交换
//     *
//     * @return {@link DirectExchange }
//     */
//    @Bean
//    public DirectExchange dlxExchange() {
//        System.out.println("🛠️ 正在创建死信交换机 (DLX): my.dlx.exchange");
//        // DLX 通常用 Direct 类型，因为路由键不变或指定死信路由键
//        return new DirectExchange(DEAD_LETTER_EXCHANGE_NAME, true, false); // 持久化
//    }
//
//
//    // ⭐ 定义重试队列 (这是第一个延迟等待层级) ⭐
//    @Bean
//    public Queue retryQueue() {
//        System.out.println("🛠️ 正在创建重试队列 (延迟 60秒): my.retry.queue");
//        Map<String, Object> args = new HashMap<>();
//        // ⭐ 核心配置 2: 消息在这个队列里等待多久变成死信（毫秒）⭐
//        args.put("x-message-ttl", 60000); // 例子：等待 60 秒
//
//        // ⭐ 核心配置 3: 消息过期变成死信后，发回哪个交换机？指向业务交换机！ ⭐
//        args.put("x-dead-letter-exchange", EXCHANGE_NAME); // 死信发回业务交换机
//
//        // ⭐ 核心配置 4: 消息过期变成死信后，使用哪个路由键发回？通常用原路由键 ⭐
//        args.put("x-dead-letter-routing-key", "api.school.add"); // 指定死信发回业务交换机时的路由键
//
//        // 队列本身也要持久化
//        return new Queue(QUEUE_RETRY_NAME, true, false, false, args);
//    }

//    @Bean
//    public Queue retryQueue1() {
//        System.out.println("🛠️ 正在创建重试队列 (延迟 60秒): my.retry.queue");
//        Map<String, Object> args = new HashMap<>();
//        // ⭐ 核心配置 2: 消息在这个队列里等待多久变成死信（毫秒）⭐
//        args.put("x-message-ttl", 60000); // 例子：等待 60 秒
//
//        // ⭐ 核心配置 3: 消息过期变成死信后，发回哪个交换机？指向业务交换机！ ⭐
//        args.put("x-dead-letter-exchange", EXCHANGE_NAME); // 死信发回业务交换机
//
//        // ⭐ 核心配置 4: 消息过期变成死信后，使用哪个路由键发回？通常用原路由键 ⭐
//        args.put("x-dead-letter-routing-key", "api.school.add"); // 指定死信发回业务交换机时的路由键
//
//        // 队列本身也要持久化
//        return new Queue(QUEUE_RETRY1_NAME, true, false, false, args);
//    }

//
//    /**
//     * ⭐ 定义重试队列绑定到 DLX ⭐
//     *
//     * @param retryQueue  重试队列
//     * @param dlxExchange dlx交换
//     * @return {@link Binding }
//     */
//    @Bean
//    public Binding retryBinding(Queue retryQueue, DirectExchange dlxExchange) {
//        System.out.println("🛠️ 将重试队列绑定到 DLX");
//        // 绑定键要和从业务队列出来到 DLX 的死信路由键匹配 (默认是原路由键 "my.routing.key")
//        return BindingBuilder.bind(retryQueue).to(dlxExchange).with("test.dlx.queue"); //
//    }


    /**
     * ⭐ 可选：定义最终失败队列 (Final DLQ) ⭐
     * 用于接收从重试队列出来，但没有被正确路由（比如业务交换机或队列被删了）
     * 或者你设计了多层重试，这是最后一层重试队列的死信目的地
     *
     * @return {@link Queue }
     */
    @Bean
    public Queue finalDlxQueue() {
        System.out.println("🛠️ 正在创建最终死信队列: test.final.dlx.queue");
        return new Queue(DEAD_LETTER_FINAL_QUEUE_NAME, true); // 持久化
    }


    /**
     * ⭐ 可选：定义一个交换机用于接收所有最终的死信 (如果需要统一处理) ⭐
     *
     * @return {@link DirectExchange }
     */
    @Bean
    public DirectExchange finalDlxExchange() {
        System.out.println("🛠️ 正在创建最终死信交换机: test.final.dlx.exchange");
        return new DirectExchange(DEAD_LETTER_FINAL_EXCHANGE_NAME, true, false);
    }


    /**
     * ⭐ 可选：将最终失败队列绑定到最终死信交换机 ⭐
     *
     * @param finalDlxQueue    最终dlx队列
     * @param finalDlxExchange 最终dlx交换
     * @return {@link Binding }
     */
    @Bean
    public Binding finalDlxBinding(Queue finalDlxQueue, DirectExchange finalDlxExchange) {
        System.out.println("🛠️ 将最终死信队列绑定到最终死信交换机");
        return BindingBuilder.bind(finalDlxQueue).to(finalDlxExchange).with("test.final.dlq.key"); // 使用一个特定的路由键
    }

}